﻿using HARTCalibrationTool.Commands.HART.CustomCommands;
using HARTCalibrationTool.SerialPortManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static HARTCalibrationTool.Commands.HART.CustomCommands.CustomCommandsBase;

namespace HARTCalibrationTool.Commands.HART
{
    public class HART135CustomCommand : CustomCommandsBase
    {
        private byte _currentCustomSubCMD = 0;
        private List<byte> _txData;
        public HART135CustomCommand(SerialPortsBase serialPortManager, string commandName, byte cmdCode, List<byte> data = null) : base(serialPortManager, commandName)
        {
            _currentCustomSubCMD = cmdCode;
            _txData = data;
        }

        protected override async Task SendCMD()
        {
            byte[] deviceID = GetDeviceID();
            List<byte> byteList = new List<byte>();
            byte[] tempData = new byte[128];

            if ((deviceID[0] == 0x00) && (deviceID[1] == 0x00) && (deviceID[2] == 0x00))
            {
                SerialPortsBase.PrintMessage("通道" + Utils.CountTrailingZeros((uint)GetCMDsChannelID()).ToString() + $", 未获取到长地址({deviceID[0]} {deviceID[1]} {deviceID[2]})!");
                return;
            }

            await Task.Run(() =>
            {
                _customCMDsCodeStruct.addressByte3 = deviceID[0];
                _customCMDsCodeStruct.addressByte4 = deviceID[1];
                _customCMDsCodeStruct.addressByte5 = deviceID[2];

                byteList.AddRange(_customCMDsCodeStruct.preamble);
                byteList.Add(_customCMDsCodeStruct.start);
                byteList.Add(_customCMDsCodeStruct.addressByte1);
                byteList.Add(_customCMDsCodeStruct.addressByte2);
                byteList.Add(_customCMDsCodeStruct.addressByte3);
                byteList.Add(_customCMDsCodeStruct.addressByte4);
                byteList.Add(_customCMDsCodeStruct.addressByte5);
                byteList.Add(_customCMDsCodeStruct.cmdID);

                if (_currentCustomSubCMD == GETPREADVALUE)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GETPREADVALUE;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == GETTMPADVALUE)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GETTMPADVALUE;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == GET_CAL_FLG)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GET_CAL_FLG;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == GET_CUR)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GET_CUR;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == GET_INFO)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GET_INFO;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == GETPREVALUE)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GETPREVALUE;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == GETTEMPVALUE)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = GETTEMPVALUE;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == SETPREFACTOR)
                {
                    int checkSum = 0;

                    if (_txData[0] == 3)
                    {
                        _customCMDsCodeStruct.size = 6 + 28;
                        _customCMDsCodeStruct.customCMD.length = 28;
                    }
                    else
                    {
                        _customCMDsCodeStruct.size = 6 + 19;
                        _customCMDsCodeStruct.customCMD.length = 19;
                    }

                    _customCMDsCodeStruct.customCMD.cmd = SETPREFACTOR;

                    _customCMDsCodeStruct.customCMD.data = _txData.GetRange(1, _txData.Count - 1);
                    checkSum = _customCMDsCodeStruct.customCMD.header1 +
                               _customCMDsCodeStruct.customCMD.header2 +
                               _customCMDsCodeStruct.customCMD.cmd +
                               _customCMDsCodeStruct.customCMD.length;

                    foreach (byte data in _customCMDsCodeStruct.customCMD.data)
                    {
                        checkSum += data;
                    }

                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(checkSum & 0xff);
                }
                else if (_currentCustomSubCMD == SETTMPFACTOR)
                {
                    int checkSum = 0;

                    if (_txData[0] == 3)
                    {
                        _customCMDsCodeStruct.size = 6 + 27;
                        _customCMDsCodeStruct.customCMD.length = 27;
                    }
                    else
                    {
                        _customCMDsCodeStruct.size = 6 + 9;
                        _customCMDsCodeStruct.customCMD.length = 9;
                    }

                    _customCMDsCodeStruct.customCMD.cmd = SETTMPFACTOR;

                    _customCMDsCodeStruct.customCMD.data = _txData.GetRange(1, _txData.Count - 1);

                    checkSum = _customCMDsCodeStruct.customCMD.header1 +
                               _customCMDsCodeStruct.customCMD.header2 +
                               _customCMDsCodeStruct.customCMD.cmd +
                               _customCMDsCodeStruct.customCMD.length;

                    foreach (byte data in _customCMDsCodeStruct.customCMD.data)
                    {
                        checkSum += data;
                    }

                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(checkSum & 0xff);
                }
                else if (_currentCustomSubCMD == SETTMPFACTOR)
                {
                    _customCMDsCodeStruct.size = 6;

                    _customCMDsCodeStruct.customCMD.cmd = SETTMPFACTOR;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    _customCMDsCodeStruct.customCMD.data = new List<byte>();
                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(_customCMDsCodeStruct.customCMD.header1 +
                                                                      _customCMDsCodeStruct.customCMD.header2 +
                                                                      _customCMDsCodeStruct.customCMD.cmd +
                                                                      _customCMDsCodeStruct.customCMD.length);
                }
                else if (_currentCustomSubCMD == SETTEMPNUM)
                {
                    int checkSum = 0;

                    if (_txData[0] == 3)
                    {
                        _customCMDsCodeStruct.size = 19;
                        _customCMDsCodeStruct.customCMD.length = 13;
                    }
                    else if (_txData[0] == 4)
                    {
                        _customCMDsCodeStruct.size = 23;
                        _customCMDsCodeStruct.customCMD.length = 17;
                    }
                    else if (_txData[0] == 5)
                    {
                        _customCMDsCodeStruct.size = 27;
                        _customCMDsCodeStruct.customCMD.length = 21;
                    }
                    else if (_txData[0] == 6)
                    {
                        _customCMDsCodeStruct.size = 31;
                        _customCMDsCodeStruct.customCMD.length = 25;
                    }
                    else if (_txData[0] == 7)
                    {
                        _customCMDsCodeStruct.size = 35;
                        _customCMDsCodeStruct.customCMD.length = 29;
                    }
                    else if (_txData[0] == 8)
                    {
                        _customCMDsCodeStruct.size = 39;
                        _customCMDsCodeStruct.customCMD.length = 33;
                    }
                    else
                    {
                        return;
                    }

                    _customCMDsCodeStruct.customCMD.cmd = SETTEMPNUM;
                    _customCMDsCodeStruct.customCMD.data = _txData;
                    checkSum = _customCMDsCodeStruct.customCMD.header1 + _customCMDsCodeStruct.customCMD.header2 +
                               _customCMDsCodeStruct.customCMD.cmd + _customCMDsCodeStruct.customCMD.length;

                    foreach (byte data in _txData)
                    {
                        checkSum += data;
                    }

                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(checkSum & 0xff);
                }
                else if (_currentCustomSubCMD == SETPRERANGE)
                {
                    int checkSum = 0;

                    _customCMDsCodeStruct.size = 14;

                    _customCMDsCodeStruct.customCMD.cmd = SETPRERANGE;
                    _customCMDsCodeStruct.customCMD.length = 8;
                    _customCMDsCodeStruct.customCMD.data = _txData;
                    checkSum = _customCMDsCodeStruct.customCMD.header1 + _customCMDsCodeStruct.customCMD.header2 +
                               _customCMDsCodeStruct.customCMD.cmd + _customCMDsCodeStruct.customCMD.length;

                    foreach (byte data in _txData)
                    {
                        checkSum += data;
                    }

                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(checkSum & 0xff);
                }
                else if (_currentCustomSubCMD == SETFACPARA)
                {
                    int checkSum = 0;

                    _customCMDsCodeStruct.size = 6;
                    _customCMDsCodeStruct.customCMD.cmd = SETFACPARA;
                    _customCMDsCodeStruct.customCMD.length = 0;
                    checkSum = _customCMDsCodeStruct.customCMD.header1 + _customCMDsCodeStruct.customCMD.header2 +
                               _customCMDsCodeStruct.customCMD.cmd + _customCMDsCodeStruct.customCMD.length;

                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(checkSum & 0xff);
                }
                else if (_currentCustomSubCMD == SETDEVADDR)
                {
                    int checkSum = 0;

                    _customCMDsCodeStruct.size = 9;

                    _customCMDsCodeStruct.customCMD.cmd = SETDEVADDR;
                    _customCMDsCodeStruct.customCMD.length = 3;
                    _customCMDsCodeStruct.customCMD.data = _txData;

                    checkSum = _customCMDsCodeStruct.customCMD.header1 + _customCMDsCodeStruct.customCMD.header2 +
                               _customCMDsCodeStruct.customCMD.cmd + _customCMDsCodeStruct.customCMD.length;

                    foreach (byte data in _txData)
                    {
                        checkSum += data;
                    }

                    _customCMDsCodeStruct.customCMD.checkSum = (byte)(checkSum & 0xff);
                }
                else
                {
                    return;
                }

                byteList.Add(_customCMDsCodeStruct.size);
                byteList.Add(_customCMDsCodeStruct.customCMD.header1);
                byteList.Add(_customCMDsCodeStruct.customCMD.header2);
                byteList.Add(_customCMDsCodeStruct.customCMD.cmd);
                byteList.Add(_customCMDsCodeStruct.customCMD.length);
                byteList.AddRange(_customCMDsCodeStruct.customCMD.data.ToArray());
                byteList.Add(_customCMDsCodeStruct.customCMD.checkSum);
                byteList.Add(_customCMDsCodeStruct.customCMD.tail);

                byte[] bytes = byteList.ToArray();
                Array.Copy(bytes, 5, tempData, 0, bytes.Length - 5);
                _customCMDsCodeStruct.parity = Utils.GetHARTCRC(tempData, (byte)(bytes.Length - 5));

                byteList.Add(_customCMDsCodeStruct.parity);

                byte[] cmdCodeBytes = byteList.ToArray();

                SerialPortsBase.PrintMessage("--> " + Utils.HexToString(cmdCodeBytes));

                SerialPortMager.SerialPortWrite(cmdCodeBytes);
            });
        }

        public override async Task ParseResponse(byte[] data)
        {
            List<string> parts = new List<string>();
            byte[] bytes = Utils.GetHARTDataFrame(data);
            string channel = ((byte)CurrentGroupChannel - 1).ToString();

            byte cmdCode = bytes[12];

            await Task.Run(() =>
            {
                if (cmdCode == CustomCommandsBase.GET_CAL_FLG)
                {
                    byte tempCalFlg = bytes[14];
                    byte pressureCalFlg = bytes[15];
                    byte currentCalFlg = bytes[16];
                    byte serUDSetFlg = bytes[17];
                    byte tempPoints = bytes[18];

                    parts.Add(channel);
                    parts.Add(tempCalFlg.ToString());
                    parts.Add(pressureCalFlg.ToString());
                    parts.Add(currentCalFlg.ToString());
                    parts.Add(serUDSetFlg.ToString());
                    SerialPortMager.NotifyObserver(HARTObserversInfo.info["HART #135#03 Get Flgs"], parts);

                    parts.Clear();
                    parts.Add(channel);
                    parts.Add(tempPoints.ToString());
                    SerialPortMager.NotifyObserver(HARTObserversInfo.info["HART #135#03 Get TPoints Flg"], parts);
                }
                else if (cmdCode == CustomCommandsBase.SETFACPARA)
                {
                    parts.Add(channel);
                    SerialPortMager.NotifyObserver(HARTObserversInfo.info["HART #135#86 Set Fac Param"], parts);
                }

                SerialPortsBase.PrintMessage("<-- " + $"{Utils.HexToString(data)}");
            });
        }
        public override void OnFailure()
        {

        }

        public override void OnSuccess()
        {

        }

        public override void OnTimeout()
        {

        }
    }
}
